﻿/**
 ******************************************************************************
 * @file	fpga-20c-chip.c
 * @brief	fpga 调试工具
 *
 *
 *
 * @section Depend
 *	-# spi_mxs.ko
 *	-# spidev.ko
 *	-# libfpga-2016.so
 *
 *
 * 2016-10-19,MenglongWu,MenglongWoo@aliyun.com
 * Copyright (C) 2017 桂林聚联科技有限公司, Inc. All Rights Reserved.
 */


#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

#include <printl.h>
#include <stdbool.h>
// #include "fpga-20c.h"
#if CONFIG_PROTOCAL_TR700_USB || CONFIG_PROTOCAL_TR700_SPI || CONFIG_PROTOCAL_TR700_USB_TK
// #include "fpga-tr700.h"
// #include "fpga-common.h"
#endif
#if CONFIG_PROTOCAL_TR600_SPI
#include "fpga-2016.h"
#endif

// #include "fpga-common.h"
#include "fpga-tr700.h"
// int fpga_otdr_isfinish(struct fpga_dev *dev, bool *isfinish);

#include "proginfo.h"
#include "printl.h"
#include "fpga_data_build.h"

#define PRINTG(fmt, ...) ___cprint(C_GREEN, C_NORMAL, fmt, ##__VA_ARGS__)
#define PRINTR(fmt, ...) ___cprint(C_RED, C_NORMAL, fmt, ##__VA_ARGS__)

#define ARRAY_SIZE_(a)   (sizeof(a) / sizeof((a)[0]))

#define STRLEN           (16)


extern int  fpga_if_wrirte_regs(struct fpga_dev *dev, unsigned int base_addr, unsigned int *regs, int len);
extern void fpga_show_env();


// #define DEF_SPI "/dev/spidev3.0"
#define DEF_SPI "/dev/spidev7.0"

static char *device = DEF_SPI;
// static uint32_t speed = 500000;
static uint32_t  speed      = 1000000;
int              is_alarm   = 0;
unsigned int     tmp_alarm  = 0;
int              is_noalarm = 0;
struct fpga_dev *dev;

int                 g_loop             = 1;
static unsigned int max_retry_isfinish = 0xffffffff;
static unsigned int max_frame          = 0xffffffff;
// 是否执行循环测试
// static int is_do_loop = 0;// 目前未用到

static char str_freq[STRLEN] = "800mhz";
static int  freq             = 800; /*TP_FREQ_800*/
;


// 默认APD电压
static char apd       = 0;
static int  is_do_apd = 0;

// 默认关闭红光
static char red       = OTDR_RL_OFF;
static int  is_do_red = 0;

static int is_do_forever = 0;
static int is_do_alive   = 0;
// 是否检查通讯光检查
static char is_do_comlaser = 0;  // 默认每次进行OTDR测试都检查，相当于测试设备

static char is_do_version    = 0;
static char is_do_tempeature = 0;
int         is_do_sw_n       = 0;
int         sw_n             = 0x01;

/* 以16进制表示 AMP 管脚
 * 0x10 只打开运放开关S1
 * 0x20 只打开运放开关S2
 * 0x30 只打开运放开关S3
 * 0x04 只打开运放开关S4
 * 0xn4 打开S1/S2/S3其中之一与S4，即0x14、0x24、0x34
 */
static unsigned int tmp_amp   = 0;
static int          is_do_amp = 0;
// 累加次数
static char str_addcount[STRLEN] = "10000";
// static long addcount;

static char str_sec[STRLEN] = "15s";   // 描述测量时间
static int  sec             = 60 * 3;  // 默认3min

// 脉冲参数
static char str_dist[STRLEN]  = "60km";  // 描述距离
static char str_pluse[STRLEN] = "40ns";  // 描述脉冲宽度
static long plus;                        // 最终fpga能识别的脉冲

// 启动OTDR测试，具体参数由其他选项指定，-t 选项使用默认参数
static int is_do_otdr = 0, is_do_ocid = 0, is_do_ocvl = 0, is_do_mdio = 0, is_do_gpio = 0, is_do_dvs = 0;
int        mdio_index = 0, gpio_index = 0;

// 激光器功率，OTDR_LASER_PW_LOW ~ OTDR_LASER_PW_HIGH
static int laser_power       = OTDR_LASER_PW_HIGH;
static int panel_ch          = 0;
static int is_do_laser_power = 0;

static int peek_ms = 0;  // 0 表示不等待，取值范围0-1000ms

// 默认波长
static int laser = 1310;

static char *pstr_adopt_pt = "32k";
static long  adopt_pt      = 32000;

static char *pstr_add_cnt = "1000";
static short add_cnt      = 1000;

static char *pstr_add_ms = "1000";
static short add_ms      = 1000;


/******************************************************************************
 * 输入提示
 ******************************************************************************/
static void print_usage(const char *prog)
{
    printf("Usage: %s [-DrtpaACw]\n", prog);
    puts(
	    "  -a <alive>  check fpga is alive\n"
	    "  -a <amp>    amplifier switch level\n"
	    "     -a 0x00000103 encode with LEVEL 2(0x01) LEVEL 1(0x03)\n"
	    "  -A <apd>    APD voltage level (how to look like '-a <amp>')\n"
	    "  -c <add>    one frame add count (100~1000 default 1000)\n"
	    "  -d <debug>  debug output (-d t -d r -d o)\n"
	    "     -d t   print send\n"
	    "     -d r   print receive\n"
	    "     -d o   print otdr data with simple format\n"
	    "  -D <device> device to use (default /dev/spidev3.0)\n"
	    "  -F <forever> for test SPI bus signal. forevery occupation SPI bus\n"
	    "  -f <freq>   OTDR sample frequency (800mhz)\n"
	    "  -L <laser>  select laser (default 1310)\n"
	    "  -P <param>  specific OTDR test param ( km/ ns/ s)\n"
	    "     -P 60km/640ns/3min\n"
	    "  -p <panel>  select laser light output from which panel channel\n"
	    "  -p <peek>   after run test.The interval of check test is finish at a time\n"
	    "  -p <pt>     how sample point at one test (default 32k)\n"
	    "  -r <red>    red ligth mode \n"
	    "     -r 0/1/s/f  off/on/slop/faster\n"
	    "  -s <speed>  transfer Baud rate (Hz)\n"
	    "  -S <switch> debug optocoupler (1-N)\n"
	    "  -t <test>   use default test param (60km/40ns/15s)\n"
	    "  -w <power>  specific laser power (1-N)\n"
	    "  -v <version> check FPGA chip version\n"
	    "  --retry <retry> retry times and exit\n"
	    "  --frame <frame> only get N frame and exit\n"

    );
    exit(1);
}

int have_param(int argc, int optind, int ind)
{
    // printf("%s(): %d %d %d %d\r\n", __FUNCTION__, __LINE__, argc, optind, ind);
    if (argc > optind + ind) {
	return 1;
    }
    else {
	return 0;
    }
}

static void parse_opts(int argc, char *argv[])
{
    int          ret;
    unsigned int tval_int;
    char        *endptr;

    while (1) {
	static const struct option lopts[] = {
	    { "alive", 1, 0, 'a' },    // 运放开关级别 --amp 0x0101
	    { "alarm", 1, 0, 'a' },    //
	    { "nalarm", 1, 0, 'n' },   //
	    { "debug", 1, 0, 'd' },    // 打印调试信息  -d t -d r -d o
	    { "device", 1, 0, 'D' },   // SPI设备       -D /dev/spidev3.0
	    { "speed", 1, 0, 's' },    // 传输速率     --speed 10000000
	    { "switch", 1, 0, 'S' },   // 光耦切换     --switch 0-9
	    { "red", 1, 0, 'r' },      // 红光开关     --red 0/1/s/f
	    { "forever", 1, 0, 'F' },  // 永远循环isalive
	    { "retry", 1, 0, 'F' },    // 重尝试几次
	    { "frame", 1, 0, 'F' },    // 读取多少次成功曲线就退出
	    { "amp", 1, 0, 'a' },      // 运放开关级别 --amp 0x0101
	    { "apd", 1, 0, 'A' },      // APD电压级别  --apd 0x0101
	    { "freq", 1, 0, 'f' },     // 采样频率     --freq 800mhz
	    { "add_ms", 1, 0, 'c' },   // 累加时间     --add_ms
	    { "param", 1, 0, 'P' },    // 测试参数     -P 60km/640ns/3min
	    { "laser", 1, 0, 'L' },    // 激光器波长    -L 1310
	    { "panel", 1, 0, 'p' },    // 面板通道      --panel 0
	    { "peek", 1, 0, 'p' },     // 询问完成间隔  --peek 32k
	    { "pt", 1, 0, 'p' },       // 采样点数      --pt 32k
	    { "reg", 1, 0, 'p' },      // 采样点数      --pt 32k
	    { "power", 1, 0, 'w' },    // 光功率        --power 1
	    { "test", 0, 0, 't' },     // 启动测试
	    { "version", 0, 0, 'v' },  // 获取FPGA版本
	    { "temp", 0, 0, 'T' },     // 获取FPGA版本
	    { "mdio", 1, 0, 'm' },     // APD电压级别  --apd 0x0101
	    { NULL, 0, 0, 0 },
	};
	int c;

	c = getopt_long(argc, argv, "d:n:D:s:S:r:F::a::a:A:f:P:p:L:C:w:t::v::T::", lopts, NULL);

	if (c == -1) {
	    break;
	}
	switch (c) {
	case 'd':
	    switch (optarg[0]) {
	    case '1':
		// EN_OTDR_DBG_LEVEL(BIT_DEF);
		break;
	    case 't':
		// EN_OTDR_DBG_LEVEL(BIT_TX);
		setenv("DBG_TX", "1", 1);

		break;
	    case 'r':
		// EN_OTDR_DBG_LEVEL(BIT_RX);
		setenv("DBG_RX", "1", 1);
		break;
	    case 'o':
		// EN_OTDR_DBG_LEVEL(BIT_OTDR_DATA);
		setenv("DBG_BIT_OTDR_DATA", "1", 1);
		break;
	    case 'p':
		setenv("DBG_P", "1", 1);
		break;
	    }
	    fpga_update_env();
	    break;
	case 'D':
	    device = optarg;
	    break;
	case 's':
	    speed = atoi(optarg);
	    break;
	case 'S':
	    // 去掉 "on" "off" 两选项，直接输入数字 1-9
	    if (0 && 0 == strcmp(optarg, "on")) {
		sw_n = -1;
	    }
	    else if (0 && 0 == strcmp(optarg, "off")) {
		sw_n = 0;
	    }
	    else {
		sscanf(optarg, "%d", &sw_n);
	    }
	    is_do_sw_n = 1;
	    break;

	case 'r':
	    switch (optarg[0]) {
	    case '0':  // -r 0 关闭红光
		red = OTDR_RL_OFF;
		break;
	    case '1':  // -r 1 红光常亮
		red = OTDR_RL_ON;
		break;
	    case 's':  // -r s 慢速闪烁
		red = OTDR_RL_SLOW;
		break;
	    case 'f':  // -r f 快速闪烁
		red = OTDR_RL_FAST;
		break;
	    }
	    is_do_red = 1;
	    break;
	case 'a':
	    // 取出有效值
	    if (strcmp("--alive", argv[optind - 2]) == 0) {
		is_do_alive = 1;
	    }
	    else if (strcmp("--amp", argv[optind - 2]) == 0) {
		sscanf(optarg, "%x", &tmp_amp);
		is_do_amp = 1;
	    }
	    else if (strcmp("--alarm", argv[optind - 2]) == 0) {
		sscanf(optarg, "%x", &tmp_alarm);
		is_alarm = 1;
	    }
	    break;
	case 'n':
	    // 取出有效值
	    if (strcmp("--nalarm", argv[optind - 2]) == 0) {
		sscanf(optarg, "%x", &tmp_alarm);
		is_noalarm = 1;
	    }
	    break;
	case 'A':
	    sscanf(optarg, "%x", &tval_int);
	    apd       = (char)tval_int;
	    is_do_apd = 1;
	    break;
	case 'c':
	    // 累加多少次
	    add_ms = atoi(optarg);
	    break;
	case 'P':
	    // ret = sscanf(optarg, "%2[^/]/%2[^/]/%2[^/]", str_dist, str_pluse, str_sec);
	    ret = sscanf(optarg,
	                 "%10[{0,1,2,3,4,5,6,7,8,9,k,m}]/"
	                 "%10[{0,1,2,3,4,5,6,7,8,9,n,s}]/"
	                 "%10[{0,1,2,3,4,5,6,7,8,9,m,i,n}]",
	                 str_dist,
	                 str_pluse,
	                 str_sec);
	    if (ret != 3) {
		printf("param unmatch :\n-P <distance/pluse/time>\n");
		exit(1);
		break;
	    }
	    is_do_otdr = 1;
	    break;
	case 'p':
	    printf("optind %d\r\n", optind);
	    if (strcmp("--panel", argv[optind - 2]) == 0) {
		sscanf(optarg, "%d", &panel_ch);
	    }
	    else if (strcmp("--peek", argv[optind - 2]) == 0) {
		sscanf(optarg, "%d", &peek_ms);
		if ((unsigned int)peek_ms > 1000) {
		    peek_ms = 0;
		}
		peek_ms *= 1000;
	    }
	    else if (strcmp("--pt", argv[optind - 2]) == 0) {
		pstr_adopt_pt = optarg;
	    }
	    break;
	case 'f':
	    strncpy(str_freq, optarg, STRLEN);
	    break;
	case 'w':
	    laser_power       = atoi(optarg);
	    is_do_laser_power = 1;
	    break;
	case 'L':
	    is_do_comlaser = 1;             // 开启通信光
	    laser          = atoi(optarg);  // 读取激光器
	    break;
	case 't':
	    // printf("argv[optind - 2] %s\r\n", argv[optind - 0]);
	    // printf("optind %d %d %s\r\n", optind, argc, argv[optind - 0] );
	    printf("%s(): %d %s\r\n", __FUNCTION__, __LINE__, argv[optind + 1]);
	    if (argc > optind) {
		if (strcmp("otdr", argv[optind - 0]) == 0) {
		    is_do_otdr = 1;
		}
		else if (strcmp("ocid", argv[optind - 0]) == 0) {
		    is_do_ocid = 1;
		}
		if (strcmp("dvs", argv[optind - 0]) == 0) {
		    is_do_dvs = 1;
		}
		else if (strcmp("ocvl", argv[optind - 0]) == 0) {
		    is_do_ocvl = 1;
		}
		else if (strcmp("mdio", argv[optind - 0]) == 0) {
		    is_do_mdio = 1;
		    mdio_index = optind;
		}
		else if (strcmp("gpio", argv[optind - 0]) == 0) {
		    is_do_gpio = 1;
		    gpio_index = optind;
		}
	    }
	    else {
		is_do_otdr = 1;
	    }


	    break;
	case 'F':
	    if (strcmp("--retry", argv[optind - 2]) == 0) {
		max_retry_isfinish = atoi(optarg);
	    }
	    else if (strcmp("--frame", argv[optind - 2]) == 0) {
		max_frame = atoi(optarg);
	    }
	    else {
		is_do_forever = 1;
	    }

	    break;
	case 'v':
	    is_do_version = 1;
	    break;
	case 'T':
	    is_do_tempeature = 1;
	    break;
	default:
	    print_usage(argv[0]);
	    break;
	}
    }
}
static void print_configure()
{
    printf("Device:       %s\n", device);

    char redmod[][5] = {
	"OFF",
	"ON",
	"SLOW",
	"FAST",
    };
    printf("Redlight      %s\n", (char *)(redmod + red));
    printf("\nOTDR:\n");
    printf("\t\tlaser     %d\n", laser);
    printf("\t\tParam     %s/%s/%s\n", str_dist, str_pluse, str_sec);
    // printf("\t\tFreq      %s\n", str_freq);
    // printf("\t\tAMP       %d on ", tmp_amp >> 4);
    // if (tmp_amp & 0x04) {
    // 	printf("S4 on\n");
    // } else {
    // 	printf("S4 off\n");
    // }
    printf("\t\tAMP       %4x\n", tmp_amp);
    printf("\t\tAPD       %4x\n", apd);
    printf("\t\tpower     %d\n", laser_power);
    printf("\t\tadd count %s\n", str_addcount);
    printf("\t\tSpeed:    %d\n\n", speed);
}
void print_testparam()
{
    printf("******** test param ********\n");
    printf("\tdistance     %s\n", str_dist);
    printf("\tlaser        %d\n", laser);
    printf("\tpulse        %s\n", str_pluse);
    printf("\tsample freq  %s\n", str_freq);
    printf("\tamp          %x\n", tmp_amp);
    printf("\tapd_vol      %d\n", apd);
    printf("\tpower        %d\n", laser_power);
    printf("******** End test param ********\n");
}


/******************************************************************************
 * 数据合法性检查
 ******************************************************************************/
// 某量程下许可的脉宽
struct list_plus
{
    char *desc;
    int   val;
};

// 许可的量程
struct list_dist
{
    char             *desc;
    int               freq;  // 测试距离与fpga采样频率关联
    struct list_plus *plus;  // 脉宽的计算与当前采样频率关联
};

struct list_plus _300m_plus[] = {
    /*TP_FREQ_300M*/
    { "5ns", 0 /*TP_PULSE_300M_5_NS*/ },
    { "10ns", 0 /*TP_PULSE_300M_10_NS*/ },
    { "20ns", 0 /*TP_PULSE_300M_20_NS*/ },
    { "40ns", 0 /*TP_PULSE_300M_40_NS*/ },
    { "80ns", 0 },
    { "160ns", 0 },
    { "640ns", 0 },
    { (char *)NULL, (int)NULL },
};
struct list_plus _1km_plus[] = {
    /*TP_FREQ_1KM*/
    { "5ns", 0 /*TP_PULSE_1KM_5_NS*/ },
    { "10ns", 0 /*TP_PULSE_1KM_10_NS*/ },
    { "20ns", 0 /*TP_PULSE_1KM_20_NS*/ },
    { "40ns", 0 /*TP_PULSE_1KM_40_NS*/ },
    { "80ns", 0 },
    { "160ns", 0 },
    { "640ns", 0 },
    { (char *)NULL, (int)NULL },
};
struct list_plus _5km_plus[] = {
    /*TP_FREQ_5KM*/
    { "10ns", 0 /*TP_PULSE_5KM_10_NS*/ },
    { "20ns", 0 /*TP_PULSE_5KM_20_NS*/ },
    { "40ns", 0 /*TP_PULSE_5KM_40_NS*/ },
    { "80ns", 0 /*TP_PULSE_5KM_80_NS*/ },
    { "160ns", 0 /*TP_PULSE_5KM_160_NS*/ },
    { "640ns", 0 },
    { "320ns", 0 },
    { (char *)NULL, (int)NULL },
};

struct list_plus _10km_plus[] = {
    { "5ns", 0 /*TP_PULSE_10KM_5_NS*/ },
    { "10ns", 0 /*TP_PULSE_10KM_10_NS*/ },
    { "20ns", 0 /*TP_PULSE_10KM_20_NS*/ },
    { "40ns", 0 /*TP_PULSE_10KM_40_NS*/ },
    { "80ns", 0 /*TP_PULSE_10KM_80_NS*/ },
    { "160ns", 0 /*TP_PULSE_10KM_160_NS*/ },
    { "320ns", 0 /*TP_PULSE_10KM_320_NS*/ },
    { "640ns", 0 },
    { "1280ns", 0 },
    { "2560ns", 0 },
    { (char *)NULL, (int)NULL },
};

struct list_plus _30km_plus[] = {
    { "5ns", 0 /*TP_PULSE_30KM_5_NS*/ },
    { "10ns", 0 /*TP_PULSE_30KM_10_NS*/ },
    { "20ns", 0 /*TP_PULSE_30KM_20_NS*/ },
    { "40ns", 0 /*TP_PULSE_30KM_40_NS*/ },
    { "80ns", 0 /*TP_PULSE_30KM_80_NS*/ },
    { "160ns", 0 /*TP_PULSE_30KM_160_NS*/ },
    { "320ns", 0 /*TP_PULSE_30KM_320_NS*/ },
    { "640ns", 0 /*TP_PULSE_30KM_640_NS*/ },
    { "1280ns", 0 },
    { "2560ns", 0 },
    { (char *)NULL, (int)NULL },
};
struct list_plus _60km_plus[] = {
    { "20ns", 0 },
    { "40ns", 0 /*TP_PULSE_60KM_40_NS*/ },
    { "80ns", 0 /*TP_PULSE_60KM_80_NS*/ },
    { "160ns", 0 /*TP_PULSE_60KM_160_NS*/ },
    { "320ns", 0 /*TP_PULSE_60KM_320_NS*/ },
    { "640ns", 0 /*TP_PULSE_60KM_640_NS*/ },
    { "1280ns", 0 /*TP_PULSE_60KM_1280_NS*/ },
    { "2560ns", 0 },
    { "5120ns", 0 },
    { (char *)NULL, (int)NULL },
};
struct list_plus _100km_plus[] = {
    { "40ns", 0 },
    { "80ns", 0 },
    { "160ns", 0 /*TP_PULSE_100KM_160_NS*/ },
    { "320ns", 0 /*TP_PULSE_100KM_320_NS*/ },
    { "640ns", 0 /*TP_PULSE_100KM_640_NS*/ },
    { "1280ns", 0 /*TP_PULSE_100KM_1280_NS*/ },
    { "2560ns", 0 /*TP_PULSE_100KM_2560_NS*/ },
    { "5120ns", 0 /*TP_PULSE_100KM_5120_NS*/ },
    { "10240ns", 0 /*TP_PULSE_100KM_10240_NS*/ },
    { "20480ns", 0 /*TP_PULSE_100KM_20480_NS*/ },
    { (char *)NULL, (int)NULL },
};

struct list_plus _180km_plus[] = {
    { "40ns", 0 },
    { "80ns", 0 },
    { "160ns", 0 /*TP_PULSE_180KM_160_NS*/ },
    { "320ns", 0 /*TP_PULSE_180KM_320_NS*/ },
    { "640ns", 0 /*TP_PULSE_180KM_640_NS*/ },
    { "1280ns", 0 /*TP_PULSE_180KM_1280_NS*/ },
    { "2560ns", 0 /*TP_PULSE_180KM_2560_NS*/ },
    { "5120ns", 0 /*TP_PULSE_180KM_5120_NS*/ },
    { "10240ns", 0 /*TP_PULSE_180KM_10240_NS*/ },
    { "20480ns", 0 /*TP_PULSE_180KM_20480_NS*/ },
    { (char *)NULL, (int)NULL },
};

struct list_dist _dist[] = {
    { "300m", 0 /*TP_FREQ_300M*/, _300m_plus },
    { "1km", 0 /*TP_FREQ_1KM*/, _1km_plus },
    { "5km", 0 /*TP_FREQ_5KM*/, _5km_plus },
    { "10km", 0 /*TP_FREQ_10KM*/, _10km_plus },
    { "30km", 0 /*TP_FREQ_30KM*/, _30km_plus },
    { "50km", 0 /*TP_FREQ_60KM*/, _60km_plus },
    { "60km", 0 /*TP_FREQ_60KM*/, _60km_plus },
    { "100km", 0 /*TP_FREQ_100KM*/, _100km_plus },
    { "180km", 0 /*TP_FREQ_180KM*/, _180km_plus },
    { "300km", 0 /*TP_FREQ_180KM*/, _180km_plus },
    { "400km", 0 /*TP_FREQ_180KM*/, _180km_plus },
    { (char *)NULL, (int)NULL, (struct list_plus *)NULL },
};
// 检查脉宽与量程之间的关系
// 语法  100km/160ns/15s
static int check_disc_pluse()
{
    struct list_dist *tdist = _dist;
    struct list_plus *tplus;


    while (tdist->desc) {
	// printf("desc %s\n", tdist->desc);
	if (0 == strcmp(str_dist, tdist->desc)) {
	    break;
	}
	tdist++;
    }
    if (tdist->desc == NULL) {
	printf("unspport distance %s\n", str_dist);
	// 列出所有支持的量程
	printf("Support distance is that:\n");
	tdist = _dist;
	while (tdist->desc) {
	    printf("\t%s\n", tdist->desc);
	    tdist++;
	}

	return -1;
    }
    freq = tdist->freq;


    tplus = tdist->plus;
    while (tplus->desc) {
	// printf("\tpluse %s\n", tplus->desc);
	if (0 == strcmp(str_pluse, tplus->desc)) {
	    plus = tplus->val;  // 获取脉冲值
	    break;
	}
	tplus++;
    }
    if (tplus->desc == NULL) {
	printf("unspport pluse %s\n", str_pluse);
	// 列出该量程下所有脉宽
	printf("Support plus is that:\n");
	tplus = tdist->plus;
	while (tplus->desc) {
	    printf("\tpluse %s\n", tplus->desc);
	    tplus++;
	}

	return -1;
    }
    plus = tplus->val;
    return 0;
}


struct list_freq
{
    char *desc;
    int   val;
};
struct list_freq _freq[] = {
    { "800mhz", /*TP_FREQ_800*/ },
    { "400mhz", /*TP_FREQ_400*/ },
    { "200mhz", /*TP_FREQ_200*/ },
    { "100mhz", /*TP_FREQ_100*/ },
    { "50mhz", /*TP_FREQ_50*/ },
    { "25mhz", /*TP_FREQ_25*/ },
    { "12mhz", /*TP_FREQ_12*/ },
    { "6mhz", /*TP_FREQ_6*/ },
    { (char *)NULL, (int)NULL },
};
static int check_freq()
{
    struct list_freq *tfreq = _freq;


    while (tfreq->desc) {
	// printf("desc %s\n", tdist->desc);
	if (0 == strcmp(str_freq, tfreq->desc)) {
	    break;
	}
	tfreq++;
    }

    if (tfreq->desc == NULL) {
	printf("unspport frequency %s\n", str_freq);
	// 列出该量程下所有脉宽
	printf("Support frequency is that:\n");
	tfreq = _freq;
	while (tfreq->desc) {
	    printf("\tfrequency %s\n", tfreq->desc);
	    tfreq++;
	}
	return -1;
    }
    return 0;
}


struct list_time
{
    char *desc;
    int   val;
};
struct list_time _time[] = {
    { "8s", 8 },
    { "15s", 15 },
    { "30s", 30 },
    { "1min", 60 },
    { "2min", 120 },
    { "3min", 180 },
    { "n", 0xffffffff },
    { (char *)NULL, (int)NULL },
};
static int check_sec()
{
    struct list_time *ttime = _time;


    while (ttime->desc) {
	// printf("desc %s\n", tdist->desc);
	if (0 == strcmp(str_sec, ttime->desc)) {
	    break;
	}
	ttime++;
    }

    if (ttime->desc == NULL) {
	printf("unspport test time%s\n", str_freq);
	// 列出该量程下所有脉宽
	printf("Support test time is that:\n");
	ttime = _time;
	while (ttime->desc) {
	    printf("\ttime %s\n", ttime->desc);
	    ttime++;
	}
	return -1;
    }
    return 0;
}
void printf_mask(unsigned long mask)
{
    unsigned long bit = 0x80000000;
    for (int i = 0; i < 32; i++) {
	if (mask & bit) {
	    printf("1");
	}
	else {
	    printf("0");
	}
	if (bit & 0x01010100) {
	    printf(" ");
	}
	bit >>= 1;
    }
}
static int check_amp()
{
    return 0;
    if (tmp_amp & (~dev->mask_amp)) {
	// printf("Warning amp mask 0x%x: %x\n", dev->mask_amp, tmp_amp);
	printf("Warning amp mask 0x%.8x: ", (unsigned int)dev->mask_amp);
	printf_mask(dev->mask_amp);
	printf("\nset amp is that  0x%.8x: ", tmp_amp);
	printf_mask(tmp_amp);
	printf("\n");
    }
    return 0;
}
static int check_laser()
{
    if (laser != 1310 && laser != 1550 && laser != 1625 &&
        laser != 1300 && laser != 850) {
	printf("unspport laser %d\n", laser);
	printf("Support laser is that:\n\t1310\n\t1550\n\t1625\n\t1300\n\t850\n");
	return -1;
    }
    return 0;
}
static int check_apd()
{
    return 0;
    if (apd & (~dev->mask_apd)) {
	printf("Warning apd mask 0x%.8x: ", (unsigned int)dev->mask_apd);
	printf_mask(dev->mask_apd);
	printf("\nset apd is that  0x%.8x: ", apd);
	printf_mask(apd);
	printf("\n");
	// return -1;
    }
    // if (apd != TP_APD_30V && apd != TP_APD_39V) {
    // 	printf("unspport APD %d\n", apd);
    // 	printf("Support APD is that:\n\t30\n\t39\n");
    // 	return -1;
    // }
    return 0;
}

static int check_laser_power()
{
    if (!(OTDR_LASER_PW_LOW <= laser_power && laser_power <= OTDR_LASER_PW_HIGH)) {
	printf("unspport laser power %d\n", laser_power);
	printf("Support laser power is that:\n\t1~4\n");
	// return -1;
    }
    return 0;
}

static int check_adopt_pt()
{
    if (0 == strcmp(pstr_adopt_pt, "32k")) {
	adopt_pt = 32000;
    }
    else if (0 == strcmp(pstr_adopt_pt, "16k")) {
	adopt_pt = 16000;
    }
    else if (0 == strcmp(pstr_adopt_pt, "64k")) {
	adopt_pt = 64000;
    }
    else if (0 == strcmp(pstr_adopt_pt, "128k")) {
	adopt_pt = 128000;
    }
    else {
	printf("unspport adopt point %s\n", pstr_adopt_pt);
	printf("Support adopt point is that:\n\t16k\n\t32k\n\t64k\n\t128k\n");
	return -1;
    }
    return 0;
}

static int check_add_cnt()
{
    int tmp;
    tmp = atoi(pstr_add_cnt);
    if (tmp > 1000 || tmp < 100) {
	printf("unspport add count %s\n", pstr_adopt_pt);
	printf("Support add count is that:\t100-1000\n");
	return -1;
    }
    add_cnt = tmp;
    return 0;
}


/******************************************************************************
 * 最终处理
 ******************************************************************************/
void build_otdr(struct fpga_test_param *param, int ch, int pluse, int freq, int amp1, int amp2, int apd, int power_lv)
{
    ///< 演示如何使用 @ref 构建默认测试参数
#if 0
	AUTO_BUILD_300M(param);
	AUTO_BUILD_1KM(param);
	AUTO_BUILD_5KM(param);
	AUTO_BUILD_10KM(param);
	AUTO_BUILD_60KM(param);
	AUTO_BUILD_100KM(param);
	AUTO_BUILD_180KM(param);
#endif

    param->laser_ch    = ch;
    param->pulse       = pluse;
    param->sample_freq = freq;
    param->adopt_pt    = 32000;
    param->add_cnt     = 10000;
    param->amp         = TP_AMP_L1(0x01);
    param->apd_vol     = apd;
    param->power       = power_lv;
    param->isrun       = 1;
}

#if 0
void do_test()
{
	struct fpga_test_param param;
	build_otdr(&param,
	           channel,
	           plus,
	           freq,
	           sw1_3[tmp_amp >> 4], sw4[tmp_amp & 0x04],
	           apd,
	           laser_power);
	printf("Run OTDR %d sec\n", sec);
	printf("Press Ctrl+C Canel\n");
	while(sec--) {
		fpga_request_test(dev, &param);
		sleep(1);
	}
}
#else

void peek_delay()
{
    if (peek_ms == 0) {
	sleep(1);
    }
    else {
	usleep(peek_ms);
    }
}
// int fpga_if_wrirte_regs_ex(struct fpga_dev *dev, unsigned int base_addr, unsigned int *regs, int len);
int do_test()
{
    struct fpga_test_param param;
    bzero(&param, sizeof(struct fpga_test_param));

    // build_otdr(&param,
    //            laser,
    //            plus,
    //            freq,
    //            sw1_3[tmp_amp >> 4], sw4[tmp_amp & 0x04],
    //            apd,
    //            laser_power);
    print_testparam();
    if (strcmp("300m", str_dist) == 0) {
	param.dist = atoi(str_dist);  // 10000;// 10Km
    }
    else {
	param.dist = atoi(str_dist) * 1000;  // 10000;// 10Km
    }

    // param.sample_freq = 800;// 使用自定义
    param.laser_ch    = laser;
    param.pulse       = atoi(str_pluse);  // 320;// 640ns;
    param.sample_freq = 0;                // 使用缺省值
    param.adopt_pt    = adopt_pt;
    param.add_ms      = add_ms;
    param.add_cnt     = add_cnt;
    param.amp         = tmp_amp;
    param.apd_vol     = apd;  // 39;	// 39V
    param.power       = laser_power;
    param.panel_ch    = panel_ch;  // 面板通道

    param.en_hw_amp = 1;
    param.hw_amp    = tmp_amp;

    param.en_hw_apd_vol = 1;
    param.hw_apd_vol    = apd;
    printf("Run OTDR %d sec\n", sec);
    printf("Press Ctrl+C Canel\n");


    // fpga_otdr_param(dev, &param);
    // sleep(1);

    unsigned char otdr_data[128000 * 4];
    int           times      = 0;
    int           wait_times = 0;
    int           success    = 0, ret;
_Again:;
    bool isfinish = false;

#if defined(CONFIG_fpga_pulse)
    char val[16]  = { 0xf0, 0xe0, 0xc1, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
    fpga_pulse(dev, &val);
#endif


#define TG60_ADDR_SW_NUM (1)
#define TG60_ADDR_SW_FUN (2)

// #define TG60_OTDR_CH (1)
#define TG60_DVS_CH      (1)
#define TG60_OTDR_CH     (2)
    // #define TG60_OTDR_CH  (1)

    int fpga_if_write_regs(struct fpga_dev * dev, unsigned int base_addr, unsigned int *regs, int len);

    int sw_num = 4;             // 光开关通道
    int sw_fun = TG60_OTDR_CH;  // 光开关通道
    // 本地存储，存储与otdr ch参数得低6bit
    // fpga_if_wrirte_regs(dev, TG60_ADDR_SW_NUM, &sw_num, sizeof(int));
    fpga_if_wrirte_regs(dev, TG60_ADDR_SW_FUN, &sw_fun, sizeof(int));
    while (-1 == fpga_otdr_param(dev, &param)) {  // 发送给FPGA
	sleep(1);
    }

    // 光开关没完全切换，需要sleep几百ms，否则测试其他光路也有光
    // sleep(1);

    while (-1 == fpga_otdr_start(dev)) {
	sleep(1);
    }
    printf("Test times : %d\n", ++times);

    if (times > max_frame) {
	exit(0);
    }

    wait_times = 0;
    int temp;
    getTemperature(&temp);
    while (g_loop) {

	peek_delay();
	fpga_otdr_isfinish(dev, &isfinish);
	if (isfinish) {
	    printf("    finish!!!\r\n");

	    ret = fpga_read_otdr_data(dev, otdr_data, param.adopt_pt * 4);
	    if (ret == 0) {
		success++;
		fpga_save_32bit("otdr-well.csv", otdr_data, param.adopt_pt * 4);
		PRINTG("succes ");
	    }
	    else {
		char fname[64];
		snprintf(fname, 64, "otdr-error-%d-%d.csv", success, times);
		fpga_save_32bit(fname, otdr_data, param.adopt_pt * 4);
		PRINTR("error  ");
	    }
	    printf(" %d/%d\n", success, times);
	    goto _Again;
	}
	else {
	    printf("\rwait... %d", wait_times);
	    fflush(stdout);
	}

	// 主要用于软件自动测试提供错误码
	wait_times++;
	if (max_retry_isfinish < wait_times) {
	    printf("retry time out (--retry=%d)\r\n", max_retry_isfinish);
	    exit(1);  // main结束程序
	}

	// End 主要用于软件自动测试提供错误码
    }
    return 0;
}
#endif


int do_otdr()
{
    if (is_do_otdr == 0) {
	return 0;
    }
    printf("******** control otdr test ********\n");
    int sw_fun = TG60_OTDR_CH;  // 光开关通道
    int sw_num = 0;
    // 本地存储，存储与otdr ch参数得低6bit
    // fpga_if_wrirte_regs(dev, TG60_ADDR_SW_NUM, &sw_num, sizeof(int));
    // fpga_if_wrirte_regs(dev, TG60_ADDR_SW_FUN, &sw_fun, sizeof(int));
    return do_test();
}

int do_dvs()
{
    if (is_do_dvs == 0) {
	return 0;
    }
    printf("******** control otdr test ********\n");

    int sw_fun = TG60_DVS_CH;  // 光开关通道
    // 本地存储，存储与otdr ch参数得低6bit
    // fpga_if_wrirte_regs(dev, TG60_ADDR_SW_FUN, &sw_fun, sizeof(int));
    return do_test();
}


int do_mdio(int argc, char **argv)
{
    if (is_do_mdio == 0) {
	return 0;
    }
    if (!have_param(argc, mdio_index, 3)) {
	printf("参数不足mdio <r/w> <phy> <reg> [data]\r\n");
	return -1;
    }
    struct mdio_tx t_buf;
    struct mdio_rx r_buf;
    unsigned int   reg, phy, value = 0;

    if (strcmp("w", argv[mdio_index + 1]) == 0) {
	if (!have_param(argc, mdio_index, 4)) {
	    printf("参数不足mdio <w> <phy> <reg> <data>\r\n");
	    return -1;
	}
	sscanf(argv[mdio_index + 4], "%x", &value);
	t_buf.option = MDIO_W;
    }
    else {
	t_buf.option = MDIO_R;
    }
    sscanf(argv[mdio_index + 2], "%x", &phy);
    sscanf(argv[mdio_index + 3], "%x", &reg);

    t_buf.phy   = phy;
    t_buf.reg   = reg;
    t_buf.value = value;

    // printf("a %d\r\n", t_buf.phy);


    // printf("phyAddr=0x%.2x, regAddr=0x%.2x, read data:0x%.4x\r\n", t_buf.phy, t_buf.reg, r_buf.value);
    fpga_send_data(
	    dev,
	    CMD_MDIO,
	    &t_buf,
	    sizeof(struct mdio_tx),
	    &r_buf,
	    sizeof(struct mdio_rx));
    printf("phyAddr=0x%.2x, regAddr=0x%.2x, read data=0x%.4x", t_buf.phy, t_buf.reg, (0xffff & r_buf.value));

    return 0;
}


int do_gpio(int argc, char **argv)
{
#if 0
    // printf("gpio_index %d\r\n", gpio_index);
    // for (int i = 0;i < 3; i++) {
    //     printf("%i %s\r\n", i, argv[gpio_index + i]);
    // }
	if (is_do_gpio == 0) {
		return 0;
	}
    if (!have_param(argc, gpio_index, 2)) {
        printf("参数不足gpio <r/w> <id> [data]\r\n");
    }
    struct gpio_tx t_buf;
    struct gpio_rx r_buf;
    int id, value;

    if (strcmp("w", argv[gpio_index + 1]) == 0) {
        if (!have_param(argc, gpio_index, 3)) {
            printf("参数不足gpio <w> <id> <data>\r\n");
            return -1;
        }
        sscanf(argv[gpio_index + 3], "%x", &value);
        t_buf.option = GPIO_W;
    }
    else {
        t_buf.option = GPIO_R;
    }
    sscanf(argv[gpio_index + 2], "%x", &id);

    t_buf.id = id;
    t_buf.value = value;
    t_buf.unuse = 0;

    // printf("a %d\r\n", t_buf.phy);
    char t[10] = {11,12,13,14,15,16,17};
    fpga_send_data(
        dev, CMD_GPIO, 
        &t_buf, sizeof(struct gpio_tx),
        // t, 4,
        &r_buf, sizeof(struct gpio_rx));
    printf("gpio id=0x%.2x, read data:0x%.4x\r\n", t_buf.id, r_buf.value);
#endif
    return 0;
}

int do_switch()
{
    if (is_do_sw_n == 0) {
	return -1;
    }
    struct fpga_test_param param;

    print_testparam();
    if (strcmp("300m", str_dist) == 0) {
	param.dist = atoi(str_dist);  // 10000;// 10Km
    }
    else {
	param.dist = atoi(str_dist) * 1000;  // 10000;// 10Km
    }

    param.laser_ch    = laser;
    param.pulse       = atoi(str_pluse);  // 320;// 640ns;
    param.sample_freq = 0;                // 使用缺省值
    // param.sample_freq = 800;// 使用自定义
    param.adopt_pt = 32000;
    param.add_ms   = 1000;
    param.add_cnt  = 1000;
    param.amp      = tmp_amp;
    param.apd_vol  = apd;  // 39;	// 39V
    param.power    = 1;
    param.panel_ch = 0;  // 无用
    // fpga_dbg_sw(dev, &param, sw_n);
    return 0;
}
#if 0
int do_comlaser()
{
	int ret;
	char *result;
	printf("******** control communicate laser checking ********\n");
	fpga_com_laser(dev, &ret);
	switch (ret) {
	case 2:
		result = "ok";
		break;
	case 1:
		result = "discover";
		break;
	default:
		result = "(unknow)";
		break;
	}
	printf("checking result %s\n", result);
	return 0;
}
#else
int do_comlaser()
{
    if (0 == is_do_comlaser) {
	return -1;
    }

    char *result;
    bool  isexist = false;
    printf("******** control communicate laser checking ********\n");

    fpga_exist_com_laser(dev, &isexist);
    switch (isexist) {
    case true:
	result = "exist";
	break;
    default:
	result = "free";
	break;
    }
    printf("checking result %s\n", result);
    return 0;
}
#endif
int do_amp()
{
    if (is_do_amp == 0 || is_do_otdr == 1) {
	return 0;
    }
    printf("******** control amplifier ********\n");

    return do_test();
}

void do_forever()
{
    int ret;
    if (is_do_forever == 0) {
	return;
    }
    int i = 0;
    while (i++ < 10000000) {
	ret = fpga_open(device, &dev, speed);
	// ret = fpga_open(device, &dev, NULL);
	switch (ret) {
	case 0:
	    printf("open device success! %d\n", i++);
	    fpga_close(dev);
	    break;
	case -1:
	    printf("bus error\n");
	    break;
	case -2:
	    printf("unknow device ID\n");
	    break;
	}
    }
}
void do_alive()
{
    int times   = 0;
    int success = 0;
    int ret     = 0;
    if (is_do_alive == 0) {
	return;
    }
    while (g_loop) {
	times++;
	ret = fpga_alive(dev);
	switch (ret) {
	case 0:
	    success++;
	    printf("\rfpga alive");
	    break;
	default:
	    printf("\rbus error");
	    break;
	}
	printf(" %d/%d", success, times);
    }
}
int do_red()
{
    if (is_do_red == 0) {
	return 0;
    }
    printf("******** control red light ********\n");
    printf("red %d\n", red);
    fpga_red_laser(dev, red);
    return 0;
}

int do_power()
{
    if (is_do_laser_power == 0 || is_do_otdr == 1) {
	return 0;
    }
    printf("******** control laser power ********\n");
    return do_test();
}
int do_version()
{
    if (is_do_version == 0) {
	return 0;
    }
    char soft = 0, hw = 0;
    if (0 != fpga_version(dev, &soft, &hw)) {
	return -1;
    }
    printf("soft %x hw %x\n", soft, hw);
    return 0;
}
int do_tempeature()
{
    if (is_do_tempeature == 0) {
	return 0;
    }
    int temp;

    fpga_otdr_temp(dev, &temp);
    printf("temp: %0.2f ℃\r\n", (float)temp / 1000.0);

    return 0;
}
#if 0
void start_otdr(struct fpga_dev *dev)
{
	struct fpga_test_param param;
	struct fpga_test_param _devparam;

	AUTO_BUILD_1KM(&param);
	_devparam.laser 	 = param.laser;
	_devparam.pulse 	 = param.pulse;
	_devparam.freq 	 	 = 0x90;//param.freq ;
	_devparam.adopt_pt 	 = 8;//param.adopt_pt / 4000;
	_devparam.add_cnt 	 = param.add_cnt;
	_devparam.power 	 = param.power;
	_devparam.amp 	 	 = param.amp;
	_devparam.apd_vol 	 = param.apd_vol;
	// _devparam.slot 	 	 = param.slot;
	// _devparam.ch 	 	 = param.ch;

	fpga_test(dev, OTDR_SETTING, (char *)&_devparam, sizeof(struct fpga_test_param) );
	fpga_test(dev, OTDR_START, NULL, 0 );
}
#endif
void start_otdr(struct fpga_dev *dev)
{
    struct fpga_test_param param;

    AUTO_BUILD_1KM(&param);
    fpga_otdr_param(dev, &param);
    // fpga_test(dev, OTDR_START, NULL, 0 );
}

#define DO_LONG 0
#define SWAP    1
int do_swap(unsigned char *buf, int len)
{
#if SWAP
    unsigned char *pchar;
    char           tmp[4];
    pchar = (unsigned char *)buf;
    for (int i = 0; i < len;) {
	tmp[0] = pchar[0];
	tmp[1] = pchar[1];
	tmp[2] = pchar[2];
	tmp[3] = pchar[3];
#if 0
		pchar[3] = tmp[0];
		pchar[2] = tmp[3];
		pchar[1] = tmp[1];
		pchar[0] = tmp[2];
#else
	pchar[3] = 0;  // tmp[0];
	pchar[2] = tmp[1];
	pchar[1] = tmp[2];
	pchar[0] = tmp[3];
#endif
	pchar += 4;
	i += 4;
    }
    return 0;

#else
    return 0;
#endif
}


void save_file(unsigned long *pt, unsigned long len)
{
    FILE *fp;
    fp = fopen("/cifs/data.txt", "wb");
    if (!fp) {
	return;
    }
    for (int i = 0; i < len; i++) {
	fprintf(fp, "%10.10d\r\n", (int)(*(pt + i) & 0x00ffffff));
	// fprintf(fp, "%8.8x\r\n", *(pt + i));
    }
    fclose(fp);
}

void read_otdr_data(struct fpga_dev *dev)
{
#if 0
#if DO_LONG
	// unsigned long buf[32000];
	// unsigned long mustbezero[4000];
#else
	unsigned char buf[32000 * 4];
	unsigned char mustbezero[4000 * 4];
#endif
	start_otdr(dev);
	sleep(1);
	fpga_test(dev, OTDR_IS_FINISH, NULL, 0 );
	sleep(1);
	fpga_test(dev, OTDR_IS_FINISH, NULL, 0 );
	// sleep(1);
	// fpga_test(dev, OTDR_ROTDR, NULL, 0 );
	int i = 0;
#if DO_LONG
	fpga_read_otdr_first(dev, OTDR_ROTDR, (unsigned long)(buf + i));
	for (int i = 1000; i < ARRAY_SIZE_(buf);) {
		fpga_read_otdr_serial(dev, (unsigned long)(buf + i));
		i += 1000;// 读取1000个点
	}
#else
	// fpga_test(dev, OTDR_ROTDR, NULL, 0 );
	// return 0;
	fpga_read_otdr_first(dev, OTDR_ROTDR, (unsigned char *)(buf + 0));
	// fpga_read_otdr_2(dev, OTDR_ROTDR, NULL, 0 ,(unsigned char)(buf + i));
	// fpga_read_otdr_2(dev, OTDR_ROTDR, NULL, 0 , ( char *)(buf+0));
	// fpga_read_otdr_2(dev, OTDR_ROTDR, (unsigned char*)(buf + i));

	for (int i = 4000; i < ARRAY_SIZE_(buf);) {
		fpga_read_otdr_serial(dev, (unsigned char *)(buf + i));
		i += 4000;// 读取1000个点
	}
#endif
	// printf("aaaaaaaaaaaaaa\n");
	// for (int i = 0;i < ARRAY_SIZE_(buf);i++) {
	// 	buf[i] = i;
	// }
	// for (int i = 0; i < ARRAY_SIZE_(buf);i++) {
	// 	buf[i] = i;
	// }
	PrintfMemory(buf, 128);


	do_swap(buf, sizeof(buf));
#if DO_LONG
	save_file(buf, ARRAY_SIZE_(buf));
#else
	save_file(buf, ARRAY_SIZE_(buf) / 4);
#endif
	// fpga_read_otdr(dev, OTDR_ROTDR, (unsigned long)mustbezero);
	// PrintfMemory(buf, 64);
#if DO_LONG
	PrintOtdrData(buf, ARRAY_SIZE_(buf));
#else
	PrintOtdrData((unsigned long *)buf, ARRAY_SIZE_(buf) / 4);
#endif

	// PrintOtdrData(mustbezero, ARRAY_SIZE_(mustbezero));
	// PrintfMemory(mustbezero, 128);
	unsigned long sum = 0;

	for (int i = 0; i < ARRAY_SIZE_(buf); i++) {
		sum += buf[i];
	}
	// sum = otdr_checksum(buf, ARRAY_SIZE_(buf));
	// printf("(buf, ARRAY_SIZE_(buf)) sum  %8.8x\n", sum);

	sum = _otdr_checksum(buf + 4, ARRAY_SIZE_(buf) - 4);
	printf("(buf+4, ARRAY_SIZE_(buf)-4) sum  %8.8x\n", sum);

	sum += _otdr_checksum(buf, 4);
	sum += _otdr_checksum(buf, 4);
	sum += _otdr_checksum(buf, 4);
	printf("pt0 * 3  %8.8x\n", sum);

	// sum = (buf+8, ARRAY_SIZE_(buf)-8);
	// printf("(buf+8, ARRAY_SIZE_(buf)-8) sum  %8.8x\n", sum);

	// sum = otdr_checksum(buf+4, ARRAY_SIZE_(buf)-8);
	// printf("1, 31999) sum  %8.8x\n", sum);
#endif
}


void do_ocid()
{
    if (is_do_ocid == 0) {
	return;
    }
    struct fpga_ocid_test_param param;
    unsigned int                ocid_data[250];
    unsigned long               rlen;

    int level = 1;

    bzero(&param, sizeof(struct fpga_ocid_test_param));
    param.ch        = 0xff;
    param.post      = 0x0203;
    param.sensitive = 0x02;


    fpga_ocid_param(dev, &param);

    fpga_ocid_sensitive(dev, 0x0002);

    fpga_ocid_start(dev);

    for (int i = 0; i < 100; i++) {

	usleep(100000);


	fpga_read_ocid_data(
		dev,
		ocid_data,
		sizeof(ocid_data) / sizeof(unsigned int),
		&rlen);
	if (level > 10) {
	    level = 0;
	}
	// fpga_ocid_sensitive(dev, level++);
	param.sensitive = level++;
	fpga_ocid_param(dev, &param);
    }
    fpga_ocid_stop(dev);
}

void do_ocvl()
{
    if (is_do_ocvl == 0) {
	return;
    }
    {
	struct ocvl_param t_buf;
	char              r_buf[32];  // 这个不能舍去
	t_buf.mode = 1;
	fpga_send_data(
		dev,
		OCVL_PARAM,
		&t_buf,
		sizeof(struct ocvl_param),
		r_buf,
		sizeof(r_buf));
    }
    {
	struct ocid_param_loss t_buf;
	char                   r_buf[32];  // 这个不能舍去
	t_buf.loss = 30;
	fpga_send_data(
		dev,
		OCID_PARAM_LOSS,
		&t_buf,
		sizeof(struct ocvl_param),
		r_buf,
		sizeof(r_buf));
    }
    {
	fpga_send_data(
		dev,
		ROUTE_DETECT,
		0,
		0,
		0,
		0);
    }
}
int do_alarm()
{
    if (!is_alarm) {
	return -1;
    }
    printf("%s()\r\n", __FUNCTION__);
    fpga_alarm(dev, tmp_alarm, 1);
    return 0;
}

int do_no_alarm()
{
    if (!is_noalarm) {
	return -1;
    }
    printf("%s()\r\n", __FUNCTION__);
    int ret = fpga_alarm(dev, tmp_alarm, 0);
    return 0;
}


void do_printl()
{
    // EN_OTDR_DBG_LEVEL(1);
    // EN_PRINT_OTDR_DATA(1);
}
void fun()
{
    int a = ~0x01;
    int b = ~0x02;
    int c = ~0x04;

    printf("a %x\n", a);
    printf("b %x\n", b);
    printf("c %x\n", c);
    printf("(a ^ b) %x\n", (a ^ b ^ c));
    printf("~(a ^ b) %x\n", ~(a ^ b ^ c));

    a = 0x01;
    b = 0x02;
    c = 0x04;
    printf("a %x\n", a);
    printf("b %x\n", b);
    printf("c %x\n", c);
    printf("(a ^ b) %x\n", (a ^ b ^ c));
    printf("~(a ^ b) %x\n", ~(a ^ b ^ c));

    struct fpga_test_param p;
    p.amp = 0x1;
    // _encode_amp(&p);
}
void fun1()
{
    struct timeval tv1, tv2, tv;

    gettimeofday(&tv1, NULL);
    printf("tv_sec: %d\n", tv1.tv_sec);
    printf("tv_usec: %d\n", tv1.tv_usec);
    sleep(1);
    gettimeofday(&tv2, NULL);
    printf("tv_sec: %d\n", tv2.tv_sec);
    printf("tv_usec: %d\n", tv2.tv_usec);
    tv.tv_sec  = (tv2.tv_sec - tv1.tv_sec);
    tv.tv_usec = (tv2.tv_usec - tv1.tv_usec);
    printf("tv_sec: %d\n", tv.tv_sec);
    printf("tv_usec: %d\n", tv.tv_usec);
}
int main(int argc, char *argv[])
{
    char **bak_argv = argv;
    // do_mdio(argc, bak_argv);
    // fun1();
    // return 0;
    int ret = 0;
    printf("sdfasf\r\n");
    // fun();
    // 读取输入选项
    parse_opts(argc, argv);
    fpga_show_env();
    do_printl();

    // 显示当前配置
    print_configure();

    do_forever();


    ret = fpga_open(device, &dev, speed);

    switch (ret) {
    case 0:
	printf("open device success!\n");
	break;
    case -1:
	printf("bus error\n");
	return -1;
    case -2:
	printf("unknow device ID\n");
	return -1;
    }


    int data;
    data = 0x1;
    // fpga_wd_reg(dev, &data);
    // fpga_rd_reg(dev, &data);
    // printf("data = %x\r\n", data);
    data += 1;

    // 检查并转换参数
    if (-1 == check_disc_pluse()) {
	return -1;
    }
    if (-1 == check_freq()) {
	return -1;
    }
    if (-1 == check_sec()) {
	return -1;
    }
    if (-1 == check_laser()) {
	return -1;
    }
    if (-1 == check_apd()) {
	return -1;
    }
    if (-1 == check_laser_power()) {
	return -1;
    }
    if (-1 == check_amp()) {
	return -1;
    }
    if (-1 == check_adopt_pt()) {
	return -1;
    }
    if (-1 == check_add_cnt()) {
	return -1;
    }
    do_alive();
#if 0

	char txbuf[100];
	int iret;
	short sret;
	long lret;
	char soft[8];
	char hw[8];

	if (argc == 2) {
		switch(argv[1][0]) {
		case 'v':
			fpga_test(dev, OTDR_VER, NULL, 0 );
			break;
		case 'r':
			txbuf[0] = 1;
			txbuf[1] = 0;
			// fpga_test(dev, OTDR_RED, txbuf, 2 );
			fpga_red_laser(dev, 1);
			break;
		case 'c':
			// fpga_test(dev, OTDR_COM, NULL, 0 );
			fpga_com_laser(dev, &iret);
			break;

		case 'C':
			fpga_test(dev, OTDR_CHECK, NULL, 0 );
			break;



		case 'g':
			start_otdr(dev);
			// fpga_otdr_start(dev);
			// fpga_test(dev, OTDR_START, NULL, 0 );
			break;
		case 's':
			// fpga_test(dev, OTDR_STOP, NULL, 0 );
			fpga_otdr_stop(dev);
			break;
		case 'f':
			// fpga_test(dev, OTDR_IS_FINISH, NULL, 0 );
			fpga_otdr_isfinish(dev);
			break;
		case 'o':

			read_otdr_data(dev);
			break;


		default:
			printf("unknow operation\n");
			exit(0);
			break;
		}

	} else {
		// fpga_test(dev, OTDR_VER, NULL, 0 );
		txbuf[0] = 1;
		txbuf[1] = 0;
		,
		fpga_test(dev, OTDR_RED, txbuf, 2 );
	}

	fpga_close(dev);
	return 0;
#endif
    // 执行指令


    do_red();
    do_power();
    do_version();
    do_comlaser();
    do_tempeature();


    // while(1) {
    // 	fpga_otdr_stop(dev);
    // 	sleep(1);
    // 	// do_comlaser();
    // 	fpga_otdr_stop(dev);
    // 	sleep(1);
    // }

    do_switch();
    do_ocid();
    do_ocvl();
    do_otdr();
    do_dvs();
    do_alarm();
    do_no_alarm();

    // do_mdio(argc, bak_argv);
    // do_gpio(argc, bak_argv);
    fpga_close(dev);


    return 0;
}

#ifdef PRJ_NAME
MODULE_PROJECT(PRJ_NAME);
#endif
#if defined(PRJ_VERSION) && defined(PRJ_PATCHLEVEL) && defined(PRJ_SUBLEVEL)
MODULE_VERSION(PRJ_VERSION "." PRJ_PATCHLEVEL "." PRJ_SUBLEVEL);
#endif

// #ifdef BUILD_DATE
MODULE_BUILD(__DATE__ " " __TIME__);
// #endif


MODULE_AUTHOR("MenglongWu <MenglongWoo@aliyun.com>");
MODULE_DESCRIPTION("otdr fpga-20c Ver.2015 test tool");
MODULE_DEPEND("spi_mxs.ko spidev.ko libfpga-2016");
PROG_GITSHA1(__GIT_SHA1__);
